﻿#include "StlImporter.h"
#include <fstream>
#include <sstream>
#include <vector>
#include "Vector3D.h"
#include <cstring>
#include <QtGlobal>

void trim(std::string &str)
{
    int s = str.find_first_not_of(" ");
    int e = str.find_last_not_of(" ");
    str = str.substr(s, e + 1);
}

std::vector<std::string> split(std::string str)
{
    trim(str);
    std::istringstream ss(str);
    std::vector<std::string> words;
    std::string word;
    while(ss >> word) {
        words.push_back(word);
    }
    return words;
}

float stringToFloat(const std::string &strValue)
{
    std::istringstream iss(strValue);
    float num;
    iss >> num;
    return num;
}

bool StlImporter::loadStl(std::string path, float ratio)
{
    std::ifstream stlfile(path, std::ios::in | std::ios::binary);
    if (!stlfile.is_open())
    {
        throw std::system_error(errno, std::system_category(), "failed to open "+path);
        return false;
    }

    char temp[80];
    stlfile.read((char *)&temp[0], 80 * sizeof(char));
    stlfile.close();

    if ((temp[0] != 's') && (temp[79] == '\n'))
    {
        return loadBinaryStl(path, ratio);
    }
    else
    {
        return loadAscllStl(path, ratio);
    }
}

/****************************************************************
* solid name
*   //一个三角面
*   facet normal ni nj nk
*       outer loop
*		    vertex v1x v1y v1z
*		    vertex v2x v2y v2z
*		    vertex v3x v3y v3z
*   	endloop
*   endfacet
*   //更多三角面···
* endsolid name
****************************************************************/
bool StlImporter::loadAscllStl(std::string path, float ratio)
{
    std::ifstream stlfile;
    stlfile.open(path, std::ios::in);
    if(!stlfile.is_open()){
        return false;
    }
    std::string line, useless;
    Vector3D point, normal;
    while (std::getline(stlfile, line)){

        trim(line);
        if(line.substr(0, 5) == "facet"){
            auto facetNormal = split(line);
            // outer loop行不处理
            std::getline(stlfile, line);
            Vector3D normal(stringToFloat(facetNormal.at(2)) * ratio, stringToFloat(facetNormal.at(3)) * ratio, stringToFloat(facetNormal.at(4)) * ratio);
            for (int j = 0; j < 3; ++j) {
                std::getline(stlfile, line);
                auto vertex = split(line);
                Vector3D point(stringToFloat(vertex.at(1)) * ratio, stringToFloat(vertex.at(2)) * ratio, stringToFloat(vertex.at(3)) * ratio);
                /*int pos = vertexPos(point);
                if(pos < 0){
                    pos = m_Vertices.size();
                    m_Vertices.push_back(point);
                    m_Normals.push_back(normal);

                }*/
                int pos = m_Vertices.size();
                m_Vertices.push_back(point);
                m_Normals.push_back(normal);
                m_Indices.push_back(pos);
            }
        }
    }
    return true;
}

/***************************************************************
* 二进制STL文件用固定的字节数来给出三角面片的几何信息。
* 【80】80个字节的文件头，用于存贮文件名
* 【4】 4 个字节的int描述模型的三角面片个数(小端存储)
* 【50*n】一个三角面片占用固定的50个字节(小端存储)，依次是:
* 【12】3个4字节浮点数(角面片的法矢量)
* 【12】3个4字节浮点数(1个顶点的坐标)
* 【12】3个4字节浮点数(2个顶点的坐标)
* 【12】3个4字节浮点数(3个顶点的坐标)个
* 【2】三角面片的最后2个字节用来描述三角面片的属性信息。
 ***************************************************************/
bool StlImporter::loadBinaryStl(std::string path, float ratio)
{

    Q_UNUSED(path)
    Q_UNUSED(ratio)
    return false;
}

int StlImporter::vertexPos(Vector3D point)
{
    int numOfPoints = m_Vertices.size();
    int index = -1;
    for (int i = 0; i < numOfPoints; ++i) {
        if(m_Vertices.at(i).sameWith(&point)){
            index = i;
            break;
        }
    }
    return index;
}

std::vector<Vector3D> StlImporter::getVertices() const
{
    return m_Vertices;
}

std::vector<Vector3D> StlImporter::getNormals() const
{
    return m_Normals;
}

std::vector<int> StlImporter::getIndices() const
{
    return m_Indices;
}
